package com.rongke.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.modelmapper.ModelMapper;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class PubLib {

    //日期的正则表达式：匹配 2004-04
    public static String DATE_PATTERN_MONTH = "^[0-9]{4}-(0[1-9]|1[0-2])$";

    //日期的正则表达式：匹配 2004-04-30 | 2004-02-29
    public static String DATE_PATTERN = "^[0-9]{4}-(((0[13578]|(10|12))-(0[1-9]|[1-2][0-9]|3[0-1]))|(02-(0[1-9]|[1-2][0-9]))|((0[469]|11)-(0[1-9]|[1-2][0-9]|30)))$";

    /**
     * 根据生日(Date)类型获取年龄
     *
     * @param birthDate 生日
     * @return
     */
    public static Integer getAge(Date birthDate) {
        if (birthDate == null) {
            return null;
        }
        int age;
        Date now = new Date();
        SimpleDateFormat format_y = new SimpleDateFormat("yyyy");
        SimpleDateFormat format_M = new SimpleDateFormat("MM");

        String birth_year = format_y.format(birthDate);
        String this_year = format_y.format(now);

        String birth_month = format_M.format(birthDate);
        String this_month = format_M.format(now);

        // 初步，估算
        age = Integer.parseInt(this_year) - Integer.parseInt(birth_year);

        // 如果未到出生月份，则age - 1
        if (this_month.compareTo(birth_month) < 0) age -= 1;
        if (age < 0) age = 0;

        return age;
    }

    /**
     * 判断字符串的编码格式
     *
     * @param str
     * @return
     */
    public static String getEncoding(String str) {
        String encode = "GB2312";
        try {
            if (str.equals(new String(str.getBytes(encode), encode))) {
                String s = encode;
                return s;
            }
        } catch (Exception exception) {
        }
        encode = "ISO-8859-1";
        try {
            if (str.equals(new String(str.getBytes(encode), encode))) {
                String s1 = encode;
                return s1;
            }
        } catch (Exception exception1) {
        }
        encode = "UTF-8";
        try {
            if (str.equals(new String(str.getBytes(encode), encode))) {
                String s2 = encode;
                return s2;
            }
        } catch (Exception exception2) {
        }
        encode = "GBK";
        try {
            if (str.equals(new String(str.getBytes(encode), encode))) {
                String s3 = encode;
                return s3;
            }
        } catch (Exception exception3) {
        }
        return "";
    }

    /**
     * 修改日期的时间
     *
     * @param date
     * @param hour
     * @param minute
     * @param second
     * @return
     */
    public static Date replaceTime(Date date, int hour, int minute, int second) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.HOUR_OF_DAY, hour);
        cal.set(Calendar.MINUTE, minute);
        cal.set(Calendar.SECOND, second);
        return cal.getTime();
    }

    /**
     * 修改日期的某一部分
     *
     * @param date
     * @param field Calendar.Type的一个值
     * @param value
     * @return
     */
    public static Date dateReplace(Date date, int field, int value) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(field, value);
        return cal.getTime();
    }

    /**
     * 创建该类的实例
     *
     * @param cls
     * @return
     */
    public static Object createObjByClass(Class cls, Object... objects) {
        try {
            if (objects == null || objects.length == 0) {
                return cls.newInstance();
            }
            Class[] paramTypes = new Class[objects.length];
            for (int i = 0; i < objects.length; i++) {
                paramTypes[i] = objects[i].getClass();
            }
            java.lang.reflect.Constructor constructor = cls.getConstructor(paramTypes);
            return constructor.newInstance(objects);
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 根据Object重新创建一个object
     *
     * @param obj
     * @return
     */
    public static Object recreateObject(Object obj) {
        try {
            return obj.getClass().newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * list转化为“,”隔开的STRING
     *
     * @param list
     * @return
     */
    public static String listToStr(List list) {
        if (list == null || list.size() == 0) return "";

        String s = list.toString();
        return s.replace("[", "").replace("]", "");
    }

    /**
     * 以“,”隔开的str转化为int类型的List
     *
     * @param str
     * @return
     */
    public static List<Integer> strToIntList(String str) {
        if (str == null) return null;

        List<Integer> list = new ArrayList<Integer>();
        for (String s : str.split(",")) {
            list.add(StrToInt(s));
        }
        return list;
    }

    /**
     * 反映射构建类
     *
     * @param clsName
     * @param parameterTypes
     * @param parameters
     * @return
     */
    public static Object constructorClass(String clsName
            , Class[] parameterTypes, Object[] parameters) {
        try {
            Class c = Class.forName(clsName);
            if (parameterTypes != null) {
                java.lang.reflect.Constructor constructor = c.getConstructor(parameterTypes);
                return constructor.newInstance(parameters);
            } else {
                return c.newInstance();
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 检测obj中的类型，自动四舍五入double和float类型
     *
     * @param obj
     * @param i
     */
    public static void roundCls(Object obj, int i) {
        for (Field field : obj.getClass().getDeclaredFields()) {
            if (double.class.equals(field.getType())
                    || Double.class.equals(field.getType())
                    || float.class.equals(field.getType())
                    || Float.class.equals(field.getType())) {
                field.setAccessible(true);
                try {
                    field.set(obj, round(field.getDouble(obj), i));
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 删除文件
     *
     * @param fileName
     * @return
     */
    public static boolean deleteFile(String fileName) {
        File file = new File(fileName);
        if (!file.exists()) {
            return true;
        } else {
            try {
                file.delete();
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
    }

    //字符串转化为日期
    public static Date strToDate(String s) {
        return strToDate(s, "yyyy-MM-dd");
    }

    // 字符串转化为日期
    public static Date strToDate(String s, String dateFormat) {
        DateFormat dd = new SimpleDateFormat(dateFormat);
        try {
            if (isNumeric(s) && s.length() == 8) {
                s = s.substring(0, 4) + "-" + s.substring(4, 6) + "-" + s.substring(6, 8);
            }
            return dd.parse(s);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 当年的第一天
     *
     * @param date
     * @return
     */
    public static Date getYearFirst(Date date) {
        Calendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.set(Calendar.MONTH, 0);
        cal.set(Calendar.DATE, 1);
        return cal.getTime();
    }

    //当月的第一天
    public static Date getMonthFirst(Date date) {
        Calendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.set(Calendar.DATE, 1);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    /**
     * 当年的最后一天
     *
     * @param date
     * @return
     */
    public static Date getYearLast(Date date) {
        Calendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.set(Calendar.MONTH, 11);
        cal.set(Calendar.DATE, 31);
        cal.set(Calendar.HOUR_OF_DAY, 23);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.SECOND, 59);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    //当月的最后一天
    public static Date getMonthLast(Date date) {
        Calendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.set(Calendar.DATE, 1);
        cal.roll(Calendar.DATE, -1);
        cal.set(Calendar.HOUR_OF_DAY, 23);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.SECOND, 59);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    //当前时间所在月份的天数
    public static int getMonthDay(Date date) {
        Calendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.set(Calendar.DATE, 1);
        cal.roll(Calendar.DATE, -1);
        return cal.get(Calendar.DATE);
    }

    //当前时间获取上个月的时间
    public static Date getSameMonthDay(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.MONTH, -1);
        return cal.getTime();
    }

    //当前时间获取上年的时间
    public static Date getSameYearDay(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.YEAR, -1);
        return cal.getTime();
    }

    /**
     * 获取两个时间之间间隔月份
     * 小的时间在前，大的在后
     * 不足月，返回1
     *
     * @param smallDate
     * @param bigDate
     * @return
     */
    public static int dateDiffMonth(Date smallDate, Date bigDate) {
        Calendar startCal = new GregorianCalendar();
        Calendar endCal = new GregorianCalendar();
        startCal.setTime(smallDate);
        endCal.setTime(bigDate);
        int m = 0;

        while (!startCal.after(endCal)) {
            startCal.add(Calendar.MONTH, 1);
            m++;
        }

        return m;
    }

    /**
     * 增加时间
     *
     * @param date
     * @param calendarType 如： Calendar.MONTH
     * @param i
     * @return
     */
    public static Date dateAdd(Date date, int calendarType, int i) {
        Calendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.add(calendarType, i);
        return cal.getTime();
    }

    /**
     * 获取两个时间之间的间隔天数
     * 不足一天也返回1
     *
     * @param date1 小的日期
     * @param date2 大的日期
     * @return
     */
    public static int dateDiffDay(Date date1, Date date2) {
        if (date1.getTime() > date2.getTime()) {
            return -1;
        }
        double f = (date2.getTime() - date1.getTime()) / (3600 * 24 * 1000);
        return (int) Math.floor(f) + 1;
    }

    //从对象中获取指定字段的值
    public static Object getObjFieldValue(Object obj, String field) {
        try {
            Field f = getObjField(obj.getClass(), field);
            f.setAccessible(true);
            return f.get(obj);
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

    //设置对象中字段的值
    public static void setObjFieldValue(Object obj, String field, Object value) {
        try {
            Field f = getObjField(obj.getClass(), field);
            f.setAccessible(true);
            f.set(obj, value);
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    //将String转为integer
    public static int StrToInt(String str) {
        int i;
        try {
            i = Integer.parseInt(str.trim());
        } catch (NumberFormatException e) {
            i = 0;
        }
        return i;
    }

    //将String转为float
    public static double StrToFloat(String str) {
        Double i;
        try {
            i = Double.parseDouble(str.trim());
        } catch (NumberFormatException e) {
            i = (double) 0;
        }
        return i;
    }

    //将obj转化成Str
    public static String ObjToStr(Object obj) {
        if (obj != null) {
            return obj.toString();
        } else {
            return "";
        }
    }

    //将obj转化成Float
    public static Double ObjToFloat(Object obj) {
        return StrToFloat(ObjToStr(obj));
    }

    //根据定义的样式,将date转化为Str
    public static String DateToStr(Date date, String format) {
        SimpleDateFormat formatter = new SimpleDateFormat(format);
        return formatter.format(date);
    }

    /**
     * 指定当前日期往前推的某个星期
     *
     * @param date 指定的时间
     * @param i    星期几,星期日为1
     */
    public static Date dateLastWeek(Date date, int i) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int iday = 7 + cal.get(Calendar.DAY_OF_WEEK) - i;
        return dateAdd(date, Calendar.DAY_OF_MONTH, -iday);
    }

    //将date转为星期
    public static String DateToWeak(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        switch (cal.get(Calendar.DAY_OF_WEEK) - 1) {
            case 0:
                return "星期日";
            case 1:
                return "星期一";
            case 2:
                return "星期二";
            case 3:
                return "星期三";
            case 4:
                return "星期四";
            case 5:
                return "星期五";
            case 6:
                return "星期六";
            default:
                return "星期日";
        }
    }

    //四舍五入，保留多少位小数
    public static double round(double d, int i) {
        return PubLib.StrToFloat(String.format("%." + i + "f", d));
    }

    //四舍五入，保留多少位小数
    public static float round(float d, int i) {
        return (float) PubLib.StrToFloat(String.format("%." + i + "f", d));
    }

    public static double floatToDouble(float f) {
        return Double.parseDouble(String.valueOf(f));
    }


    //Str首字母大写
    public static String fCharToUpper(String str) {
        char[] array = str.toCharArray();
        array[0] -= 32;
        return String.valueOf(array);
    }

    //反映射Object中的field
    //如果找不到，则查询父类中的字段
    public static Field getObjField(Class cls, String f) {
        try {
            return cls.getDeclaredField(f);
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        if (cls != Object.class) {
            return getObjField(cls.getSuperclass(), f);
        } else {
            return null;
        }
    }

    //Map中key对应Object字段值转换为Array
    public static Object[] getItemByObj(Map<String, ?> map, Object obj) {
        Object[] cells = new Object[map.size()];
        int i = 0;
        for (Map.Entry<String, ?> entry : map.entrySet()) {
            cells[i] = PubLib.getObjFieldValue(obj, entry.getKey());
            i++;
        }
        return cells;
    }

    //通过链表得到组装的数据集
    public static Object[] getItemByObj(Collection<?> containerPropertyIds, Object obj) {
        Object[] cells = new Object[containerPropertyIds.size()];
        Iterator it = containerPropertyIds.iterator();
        for (int i = 0; i < containerPropertyIds.size(); i++) {
            cells[i] = PubLib.getObjFieldValue(obj, it.next().toString());
        }
        return cells;
    }

    //根据field的类型判断返回不同的CLASS
    public static Class<?> getClsByField(Field f) {
        if (String.class.equals(f.getType())) {
            return String.class;
        } else if (int.class.equals(f.getType()) || Integer.class.equals(f.getType())) {
            return Integer.class;
        } else if (double.class.equals(f.getType()) || Double.class.equals(f.getType())) {
            return Double.class;
        } else if (boolean.class.equals(f.getType()) || Boolean.class.equals(f.getType())) {
            return Boolean.class;
        } else if (Date.class.equals(f.getType())) {
            return Date.class;
        } else {
            return Object.class;
        }
    }

    public static int getDateField(Date workDay, int calendar) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(workDay);
        return cal.get(calendar);
    }

    public static boolean isNumeric(String str) {
        Pattern pattern = Pattern.compile("[0-9]*");
        Matcher isNum = pattern.matcher(str);
        if (!isNum.matches()) {
            return false;
        }
        return true;
    }

    /**
     * 去掉日期中的时间
     *
     * @param date Date类型日期
     * @return
     */
    public static Date dateRemoveTime(Date date) {
        return PubLib.strToDate(PubLib.DateToStr(date, "yyyy-MM-dd"));
    }

    /**
     * 获取附件的保存路径（部署目录+/ATTACHMENT)
     *
     * @param request
     * @return
     */
    public static String getFileDir(HttpServletRequest request) {
        String path = request.getSession().getServletContext().getRealPath("/");
        File file = new File(path);
        if (!file.exists()) {
            file.mkdirs();
        }
        return path + "/ATTACHMENT";
    }

    private static final char UNDERLINE = '_';

    /**
     * 如：
     * userName --> user_name
     *
     * @param param
     * @return
     */
    public static String camelToUnderline(String param) {
        if (param == null || "".equals(param.trim())) {
            return "";
        }
        int len = param.length();
        StringBuilder sb = new StringBuilder(len);
        for (int i = 0; i < len; i++) {
            char c = param.charAt(i);
            if (Character.isUpperCase(c)) {
                sb.append(UNDERLINE);
                sb.append(Character.toLowerCase(c));
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    /**
     * 如：
     * user_name --> userName
     * user_name_ --> userName
     *
     * @param param
     * @return
     */
    public static String underlineToCamel(String param) {
        if (param == null || "".equals(param.trim())) {
            return "";
        }
        int len = param.length();
        StringBuilder sb = new StringBuilder(len);
        for (int i = 0; i < len; i++) {
            char c = param.charAt(i);
            if (c == UNDERLINE) {
                if (++i < len) {
                    sb.append(Character.toUpperCase(param.charAt(i)));
                }
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    /**
     * 如：
     * user_name --> userName
     *
     * @param param
     * @return
     */
    public static String underlineToCamel2(String param) {
        if (param == null || "".equals(param.trim())) {
            return "";
        }
        StringBuilder sb = new StringBuilder(param);
        Matcher mc = Pattern.compile("_").matcher(param);
        int i = 0;
        while (mc.find()) {
            int position = mc.end() - (i++);
            sb.replace(position - 1, position + 1, sb.substring(position, position + 1).toUpperCase());
        }
        return sb.toString();
    }

    private static void convert(Object json, int type) {
        if (json instanceof JSONArray) {
            JSONArray arr = (JSONArray) json;
            for (Object obj : arr) {
                convert(obj, type);
            }
        } else if (json instanceof JSONObject) {
            JSONObject jo = (JSONObject) json;
            Set<String> keys = jo.keySet();
            String[] array = keys.toArray(new String[keys.size()]);
            for (String key : array) {
                Object value = jo.get(key);
                String[] key_strs = key.split("_");
                if (key_strs.length > 1) {
                    StringBuilder sb = new StringBuilder();
                    for (int i = 0; i < key_strs.length; i++) {
                        String ks = key_strs[i];
                        if (!"".equals(ks)) {
                            if (i == 0) {
                                sb.append(ks);
                            } else {
                                int c = ks.charAt(0);
                                if (c >= 97 && c <= 122) {
                                    int v = c - 32;
                                    sb.append((char) v);
                                    if (ks.length() > 1) {
                                        sb.append(ks.substring(1));
                                    }
                                } else {
                                    sb.append(ks);
                                }
                            }
                        }
                    }
                    jo.remove(key);
                    jo.put(sb.toString(), value);
                }
                convert(value, type);
            }
        }
    }

    /**
     * 下划线转驼峰形式
     *
     * @param o
     * @return
     */
    public static Object convert(Object o) {
        String json = JSONObject.toJSONString(o);
        Object obj = JSON.parse(json);
        convert(obj, 1);
        return obj;
    }

    /**
     * 实体复制
     *
     * @param source 实体
     * @return <D>
     */
    public static <D> D copyObject(Object source, Class<D> destinationType) {
        if (null == source) {
            return null;
        }
        ModelMapper model = new ModelMapper();
        return model.map(source, destinationType);
    }

    /**
     * 实体转JSONObject(忽略指定属性)
     *
     * @param source 实体
     * @param arr    需要忽略的属性
     * @param map    需要添加的属性和属性值
     * @return 返回JSONObject
     */
    public static JSONObject copyToJSONObject(Object source, String[] arr, Map<String, Object> map) {
        String json = JSONObject.toJSONString(source);
        JSONObject jsonObject = JSON.parseObject(json);
        if (map != null) {
            Set<String> strings = map.keySet();
            for (String string : strings) {
                jsonObject.put(string, map.get(string));
            }
        }

        if (null != arr) {
            for (String str : arr) {
                jsonObject.put(str, null);
            }
        }

        return jsonObject;
    }

    public static JSONObject copyToJSONObject(Object source, String[] arr) {
        if (null == source) {
            return null;
        }
        return copyToJSONObject(source, arr, null);
    }

    /**
     * 实体转JSONObject(返回指定属性)
     *
     * @param source 实体
     * @param arr    需要返回的属性
     * @return 返回JSONObject
     */
    public static JSONObject copyToJSONObjectAppoint(Object source, String[] arr) {
        String json = JSONObject.toJSONString(source);
        JSONObject jsonObject = JSON.parseObject(json);
        JSONObject jsonObject1 = new JSONObject();
        for (String str : arr) {
            jsonObject1.put(str, jsonObject.get(str));
        }
        return jsonObject1;
    }

}
